package rsi.mesoscopic.ui;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import rsi.mesoscopic.model.NetworkModel;
import rsi.mesoscopic.view.DrawCanvas;
import rsi.mesoscopic.view.NetworkView;

public class MesoscopicSimulationPanel extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 5509837138304644998L;

	private DrawCanvas mDrawCanvas;
	
	private NetworkView mNetworkView;
	
	private NetworkModel mModel;
	
	private JPanel mControlPanel;
	
	private JButton mBtnNextStep;
	
	private JButton mBtnPreviousStep;
	
	private JButton mBtnPause;
	
	private JButton mBtnContinue;
	
	private JTextField mTxtCurrentStep;
	
	private JSpinner mSprTimestep;
	
	private SpinnerNumberModel mSprModel;
	
	private boolean mPaused = false;
	
	private static int mStepTime = 1000;
	
	public MesoscopicSimulationPanel(NetworkModel model) {
		mModel = model;
		init();
	}
	
	protected void init() {
		//Setup screen layout
		setLayout(new BorderLayout());
		
		//Setup graphical viewer
		mNetworkView = new NetworkView(mModel);
		mDrawCanvas = new DrawCanvas();
		mDrawCanvas.addView(mNetworkView);
		add(mDrawCanvas, BorderLayout.CENTER);
		
		//Setup control panel
		setupControlPanel();
		add(mControlPanel, BorderLayout.NORTH);
		
	}

	private void setupControlPanel() {
		mControlPanel = new JPanel();
		mControlPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
		
		ImageIcon previousIcon = new ImageIcon(MesoscopicSimulationPanel.class.getResource("/rsi/mesoscopic/images/media-previous_16x16.png"));
		mBtnPreviousStep = new JButton(previousIcon);
		mBtnPreviousStep.addActionListener(mActionPreviousStep);
		mControlPanel.add(mBtnPreviousStep);
	
		ImageIcon pauseIcon = new ImageIcon(MesoscopicSimulationPanel.class.getResource("/rsi/mesoscopic/images/media-pause_16x16.png"));
		mBtnPause = new JButton(pauseIcon);
		mBtnPause.addActionListener(mActionPause);
		mControlPanel.add(mBtnPause);
		
		ImageIcon continueIcon = new ImageIcon(MesoscopicSimulationPanel.class.getResource("/rsi/mesoscopic/images/media-play_16x16.png"));
		mBtnContinue = new JButton(continueIcon);
		mBtnContinue.addActionListener(mActionContinue);
		mControlPanel.add(mBtnContinue);
		
		ImageIcon nextIcon = new ImageIcon(MesoscopicSimulationPanel.class.getResource("/rsi/mesoscopic/images/media-next_16x16.png"));
		mBtnNextStep = new JButton(nextIcon);
		mBtnNextStep.addActionListener(mActionNextStep);
		mControlPanel.add(mBtnNextStep);

		mTxtCurrentStep = new JTextField("0", 8);
		JLabel stepLabel = new JLabel("Step:");
		mControlPanel.add(stepLabel);
		mControlPanel.add(mTxtCurrentStep);
		
		mSprTimestep = new JSpinner();
		mSprModel = new SpinnerNumberModel(1000, 200, 100000, 100);
		mSprModel.addChangeListener(mSprChangeListener);
		mSprTimestep.setModel(mSprModel);
		mControlPanel.add(new JLabel("Step time:"));
		mControlPanel.add(mSprTimestep);
		
		mBtnPreviousStep.setEnabled(false);
		mBtnPause.setEnabled(false);
	}
	
	public NetworkModel getModel() {
		return mModel;
	}

	public void setModel(NetworkModel model) {
		this.mModel = model;
		//TODO update model on view
	}
	
	private void setContiuousRun() {
		mBtnPreviousStep.setEnabled(false);
		mBtnNextStep.setEnabled(false);
		mBtnContinue.setEnabled(false);
		mBtnPause.setEnabled(true);
	}
	
	private void setStepByStepRun() {
		mBtnPreviousStep.setEnabled(mModel.getCurrentStep() > 0);
		mBtnNextStep.setEnabled(mModel.hasMoreSteps());
		mBtnContinue.setEnabled(true);
		mBtnPause.setEnabled(false);
	}
	
	private ActionListener mActionNextStep = new ActionListener() {
		
		@Override
		public void actionPerformed(ActionEvent e) {
			mModel.nextStep();
			mTxtCurrentStep.setText(mModel.getCurrentStep()+"");
			mBtnPreviousStep.setEnabled(mModel.getCurrentStep() > 0);
			mBtnNextStep.setEnabled(mModel.hasMoreSteps());
			mDrawCanvas.update();
		}
	};
	
	private ActionListener mActionPreviousStep = new ActionListener() {
		
		@Override
		public void actionPerformed(ActionEvent e) {
			mModel.previousStep();
			mTxtCurrentStep.setText(mModel.getCurrentStep()+"");
			mBtnPreviousStep.setEnabled(mModel.getCurrentStep() > 0);
			mBtnNextStep.setEnabled(mModel.hasMoreSteps());
			mDrawCanvas.update();
		}
	};
	
	private ActionListener mActionPause = new ActionListener() {

		@Override
		public void actionPerformed(ActionEvent e) {
			synchronized(mContinuousRunnable) {
				mPaused = true;
			}
			
			setStepByStepRun();
		}
		
	};
	
	private ActionListener mActionContinue = new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
			setContiuousRun();
			synchronized (mContinuousRunnable) {
				mPaused = false;
			}
			Thread t = new Thread(mContinuousRunnable);
			t.start();
		}
	};
	
	private ChangeListener mSprChangeListener = new ChangeListener() {
		@Override
		public void stateChanged(ChangeEvent e) {
			mStepTime = (Integer) mSprModel.getValue();
		}
	};
	
	private Runnable mContinuousRunnable = new Runnable() {
		@Override
		public void run() {
			
			while(mModel.hasMoreSteps()) {
				mModel.nextStep();
				mDrawCanvas.update();
				
				SwingUtilities.invokeLater(new Runnable() {
					@Override
					public void run() {
						mTxtCurrentStep.setText(mModel.getCurrentStep()+"");
					}
				});
				
				try {
					Thread.sleep(mStepTime);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				synchronized(this) {
					if(mPaused) {
						return;
					}
				}
			}
			
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					setStepByStepRun();
				}
			});

		}
	};
}
